home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Applications
/
Communication
/
NewsBase
/
Source
/
INewsBase.m
< prev
next >
Wrap
Text File
|
1993-01-12
|
21KB
|
715 lines
/*$Copyright:
* Copyright (C) 1992.5.22. Recruit Co.,Ltd.
* Institute for Supercomputing Research
* All rights reserved.
* NewsBase by ISR, Kazuto MIYAI, Gary ARAKAKI, Katsunori SUZUKI, Kok-meng Lue
*
* You may freely copy, distribute and reuse the code in this program under
* following conditions.
* - to include this notice in the source code, if it is to be distributed
* with source code.
* - to add the file named "COPYING" within the code, which shall include
* GNU GENERAL PUBLIC LICENSE(*).
* - to display an acknowledgement in binary code as follows: "This product
* includes software developed by Recruit Co.,Ltd., ISR."
* - to display a notice which shall state that the users may freely copy,
* distribute and reuse the code in this program under GNU GENERAL PUBLIC
* LICENSE(*)
* - to indicate the way to access the copy of GNU GENERAL PUBLIC LICENSE(*)
*
* (*)GNU GENERAL PUBLIC LICENSE is stored in the file named COPYING
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
$*/
#import "INewsBase.h"
#import "INntpIO.h"
#import "IDataGroupBrowser.h"
#import "IItemHeaderBrowser.h"
#import "INXBrowserCellWithLinkedObject.h"
#import "INewsgroupInfoD.h"
#import "IUifNode.h"
#import "SideSplitView.h"
#import "IBaseControl.h"
#import "IFolderDockMatrix.h"
#import "data_types.h"
#import <appkit/appkit.h>
#import <stdio.h>
#import <string.h>
#import <mach/mach.h>
#import <defaults/defaults.h>
#import "data_types.h"
#import "errdebug.h"
#import "Localization.h"
#define LoStr(key) doLocalString(NULL,key,NULL)
//#define NNTPHOST "isrgwy"
@implementation INewsBase
+ (char *)label
{
return ("NewsBase...");
}
- init
{
BrowserMode newsgroupMode, articleMode;
id loadingAlertPanel;
NXModalSession loadingModalSession;
[super init];
iNntpIO = nil;
/* make zone for NewsBase */
newsbaseZone = NXCreateZone (vm_page_size, vm_page_size, YES);
/* load window into screen */
LoadLocalNib("NewsBase.nib",self,NO,newsbaseZone);
/*
[NXApp loadNibSection:"NewsBase.nib" owner:self
withNames:NO fromZone:(NXZone *)newsbaseZone];
*/
/* open openNewsBasePanel */
if ([self openNewsBasePanel] == 0) {
/* click cancel */
[NXApp delayedFree:self];
return(nil);
}
/* click OK */
/* read default database for newsgroupMode & articleMode */
if (strcmp(NXGetDefaultValue(OWNER, NEWSGROUPBROWSERMODE),"List")==0) {
newsgroupMode = Flat;
} else {
newsgroupMode = Tree;
}
if (strcmp(NXGetDefaultValue(OWNER, ARTICLEBROWSERMODE),"ByReference")
== 0) {
articleMode = Tree;
} else if (strcmp(NXGetDefaultValue(OWNER, ARTICLEBROWSERMODE),"BySubject")
== 0) {
articleMode = BySubject;
} else if (strcmp(NXGetDefaultValue(OWNER, ARTICLEBROWSERMODE),"ByKeyword")
== 0) {
articleMode = ByKeyword;
} else {
articleMode = Flat;
}
[iNntpIO setArticleMode:articleMode];
/* open connection to nntp server */
loadingAlertPanel = NXGetAlertPanel(LoStr("NewsBase"),
LoStr("Connecting to nntp server..., please wait"),
NULL, NULL, NULL);
[NXApp beginModalSession:&loadingModalSession for:loadingAlertPanel];
iNntpIO = [[INntpIO allocFromZone:newsbaseZone]
initServer:iNntpHost allNews:iAllNewsFlag
newsGroupMode:(BrowserMode)newsgroupMode
articleMode:(BrowserMode)articleMode];
if (iNntpIO==nil) {
/* failed to connect to server */
/* stop modal loop */
[NXApp endModalSession:&loadingModalSession];
[loadingAlertPanel orderOut:self];
NXFreeAlertPanel(loadingAlertPanel);
/* free objects */
[oNewsReader free];
// [oViewControlPanel free];
[iNntpIO free];
[super free];
return nil;
}
[NXApp endModalSession:&loadingModalSession];
[loadingAlertPanel orderOut:self];
NXFreeAlertPanel(loadingAlertPanel);
// set hierarchy of view and size from user's default data base
[self _readWindowInfoFromDefaultDBandSetupViews];
/* make NewsBase window */
[self _setUpInterfaceWindow];
return self;
}
- _readWindowInfoFromDefaultDBandSetupViews
{
const char *buffer;
NXRect newsbaseRect;
NXSize folderDockSize, browserSplitViewSize, leftSideSize, rightSideSize;
NXRect frameRect;
/* setup for side spilited view, newsgroup browser and article browser */
[oNewsgroupView setAutoresizeSubviews:YES];
[oNewsgroupView addSubview:oNewsfolderScroll];
[oNewsgroupView addSubview:oNewsGroupNXBrowser];
if ((buffer = NXGetDefaultValue(OWNER, NNTPBROWSER_FRAME)) != 0 &&
sscanf(buffer, "(%f,%f):(%f,%f):(%f,%f):(%f,%f):(%f,%f):(%f,%f)",
&newsbaseRect.origin.x,&newsbaseRect.origin.y,
&newsbaseRect.size.width, &newsbaseRect.size.height,
&folderDockSize.width, &folderDockSize.height,
&browserSplitViewSize.width, &browserSplitViewSize.height,
&leftSideSize.width, &leftSideSize.height,
&rightSideSize.width, &rightSideSize.height
) == 12) {
[oNewsReader placeWindow:&newsbaseRect];
[oNewsgroupView sizeTo:leftSideSize.width :leftSideSize.height];
[oArticleNXBrowser sizeTo:rightSideSize.width :rightSideSize.height];
[oNewsfolderDock sizeTo:folderDockSize.width :folderDockSize.height];
[oNewsfolderDockMatrix sizeTo:folderDockSize.width :folderDockSize.height];
[oBrowserSplitView sizeTo:browserSplitViewSize.width
:browserSplitViewSize.height];
}
/* setup side split view */
[oBrowserSplitView setRightView:oArticleNXBrowser];
[oBrowserSplitView setLeftView:oNewsgroupView];
/* setup for newsgroup folder dock and bowser */
[oSplitView addSubview:oNewsfolderDock];
[oSplitView addSubview:oBrowserSplitView];
[oBrowserSplitView initViews];
[oNewsfolderScroll setAutoresizeSubviews:YES];
// [oNewsfolderScrollMatrix notifyAncestorWhenFrameChanged:YES];
[oNewsfolderScrollMatrix getFrame:&frameRect];
frameRect.origin.x = frameRect.origin.y = 0.0;
[oNewsfolderScrollMatrix setFrame:&frameRect];
[oNewsfolderScrollDocView getFrame:&frameRect];
frameRect.origin.x = frameRect.origin.y = 0.0;
[oNewsfolderScrollDocView setFrame:&frameRect];
[oNewsfolderScrollDocView addSubview:oNewsfolderScrollMatrix];
[oNewsfolderScrollDocView setAutoresizeSubviews:NO];
[oNewsfolderScroll setDocView:oNewsfolderScrollDocView];
// set delegate for resizing behavior when sliding divider bar
// [oSplitView setDelegate:oNewsfolderDockMatrix];
[oSplitView setDelegate:self];
// set root cell (next station icon) for newsgroup folder view
// oNewsfolderScroll is scroll view,
// which document view is IFolderScrollMatrix
[oNewsfolderScrollMatrix setRootName:[iNntpIO rootName]];
[oNewsfolderDockMatrix setRootName:[iNntpIO rootName]];
[[oNewsReader contentView] displayFromOpaqueAncestor:NULL :0 :YES];
[oNewsfolderDockMatrix registerCells];
return self;
}
- _setUpInterfaceWindow
{
/*
* The objects in this module are:
* INewsBase initializes the module.
* NewsGroupTree holds the newsgroups in a tree structure.
* NewsGroupTreeControl initializes and maintains the NewsGroupTree.
*/
/* set up news group browser */
[oNewsGroupNXBrowser setIOmodule:iNntpIO];
if ([iNntpIO newsGroupMode]==Flat) {
[oNewsGroupNXBrowser setMaxVisibleColumns:1];
} else {
[oNewsGroupNXBrowser setMaxVisibleColumns:4];
}
/* set up article browser */
[oArticleNXBrowser setIOmodule:iNntpIO];
if ([iNntpIO articleMode]==Flat) {
[oArticleNXBrowser setMaxVisibleColumns:1];
} else {
[oArticleNXBrowser setMaxVisibleColumns:2];
}
/* load cell into NewsGroupBrowser */
[oNewsGroupNXBrowser setRootListnode:[iNntpIO subDirectoryOf:nil]];
[oNewsGroupNXBrowser loadColumnZero];
/* set up interaction of DataGroupBrowser,ItemRepBrowser,ItemBrowser */
[oNewsGroupNXBrowser setItemRepUIF:oArticleNXBrowser];
[oArticleNXBrowser setDataGroupUIF:oNewsGroupNXBrowser];
/* set control panel */
[oNewsReader setDelegate:self];
[self setArticleBrowserMode];
/* set up window for getting article number */
[iNntpIO setOGetArticleNumWindow:oGetArticleNumWindow];
[iNntpIO setOGetArticleNumField:oGetArticleNumField];
[iNntpIO setIPercentageView:oPercentageView];
[oArticleNumOKButton setTarget:iNntpIO];
[oArticleNumCancelButton setTarget:iNntpIO];
[oArticleNumOKButton setAction:@selector(okArticleNumWindow:)];
[oArticleNumCancelButton setAction:@selector(cancelArticleNumWindow:)];
DBG(10, fprintf(stderr," NewsBase is made\n"));
return self;
}
- (char *)label
{
static char labelString[64];
sprintf (labelString, "NewsBase: %.53s", iNntpHost);
return labelString;
}
- show:sender
{
unsigned int windowNum;
NXRect oldRect;
[oNewsReader display];
[oNewsReader makeKeyAndOrderFront:self];
// register window for accepting file icons
NXConvertWinNumToGlobal([oNewsReader windowNum], &windowNum);
[[NXApp appSpeaker] setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
[[NXApp appSpeaker] registerWindow:windowNum
toPort:[[NXApp appListener] listenPort]];
// these statements should not be needed here. but
// I could not register rectangle of cells during setting up views
// in "_readWindowInfoFromDefaultDBandSetupViews" above.
[oNewsfolderDockMatrix registerCells];
[oNewsfolderScrollMatrix registerCells];
[oSplitView getFrame:&oldRect];
[self splitView:oSplitView
resizeSubviews:(const NXSize *)&(oldRect.size)];
return(self);
}
- terminateProc
{
[self _saveWindowInfoToDefaultDB];
return self;
}
- (BOOL)postArticle:(const char *)article length:(int)length
{
return([iNntpIO postArticle:article length:length]);
}
- (BOOL)sendArticle:(const char *)messageId
{
return([iNntpIO sendArticle:messageId]);
}
- newsGroupTreeControl
{
return iNntpIO;
}
- toggleNewsGroupBrowser:sender
{
if ([iNntpIO toggleNewsGroupMode:sender]==Flat) {
[oNewsGroupNXBrowser setMaxVisibleColumns:1];
NXWriteDefault(OWNER, NEWSGROUPBROWSERMODE, "List");
} else {
[oNewsGroupNXBrowser setMaxVisibleColumns:4];
NXWriteDefault(OWNER, NEWSGROUPBROWSERMODE, "Browser");
}
/* reset newsgroup browser and redraw new browser */
[oNewsGroupNXBrowser setRootListnode:[iNntpIO subDirectoryOf:nil]];
[oNewsGroupNXBrowser loadColumnZero];
return self;
}
- toggleArticleBrowser:sender
{
[iNntpIO toggleArticleMode:sender];
[self setArticleBrowserMode];
return(self);
}
- setArticleBrowserMode
{
id node;
id itemHeaderslist;
switch ([iNntpIO articleMode]) {
case Flat:
[oArticleNXBrowser setMaxVisibleColumns:1];
[oArticleNXBrowser setTitle:LISTCOL0TITLE ofColumn:0];
NXWriteDefault(OWNER, ARTICLEBROWSERMODE, "List");
break;
case Tree:
[oArticleNXBrowser setMaxVisibleColumns:2];
[oArticleNXBrowser setTitle:BROWSERCOL0TITLE ofColumn:0];
NXWriteDefault(OWNER, ARTICLEBROWSERMODE, "ByReference");
break;
case BySubject:
[oArticleNXBrowser setMaxVisibleColumns:2];
[oArticleNXBrowser setTitle:SUBJECTCOL0TITLE ofColumn:0];
NXWriteDefault(OWNER, ARTICLEBROWSERMODE, "BySubject");
break;
case ByKeyword:
[oArticleNXBrowser setTitle:KEYWORDCOL0TITLE ofColumn:0];
[oArticleNXBrowser setMaxVisibleColumns:2];
NXWriteDefault(OWNER, ARTICLEBROWSERMODE, "ByKeyword");
break;
}
/* reset article browser */
node = [self _nodeForSelectedCellInBrowser:oNewsGroupNXBrowser];
itemHeaderslist = [iNntpIO itemHeadersOf:node];
/* update article browser */
[oArticleNXBrowser setRootListnode:itemHeaderslist];
[oArticleNXBrowser loadColumnZero];
return(self);
}
- setReadFlagToAll:sender
{
id node;
id itemHeaderslist;
[iNntpIO setReadFlag:(ReadFlag)ALL];
node = [self _nodeForSelectedCellInBrowser:oNewsGroupNXBrowser];
itemHeaderslist = [iNntpIO itemHeadersOf:node];
/* update article browser */
[oArticleNXBrowser setRootListnode:itemHeaderslist];
[oArticleNXBrowser loadColumnZero];
/* set read flag to default */
[iNntpIO setReadFlag:(ReadFlag)UNMARKEDONLY];
return self;
}
- markAllArticleAsRead:sender
{
id lastColumnMatrix;
switch(NXRunAlertPanel(LoStr("NewsBase"),
LoStr("Cannot Undo! all article will be marked as read."),
LoStr("OK"),LoStr("Cancel"),NULL)) {
case NX_ALERTDEFAULT:
lastColumnMatrix = [oNewsGroupNXBrowser matrixInColumn:
[oNewsGroupNXBrowser lastColumn]];
[lastColumnMatrix sendAction:@selector(markAllArticleOfCell:)
to:self forAllCells:NO];
break;
case NX_ALERTALTERNATE:
return(self);
}
/* reset article browser */
[oArticleNXBrowser setRootListnode:nil];
[oArticleNXBrowser loadColumnZero];
return self;
}
- markAllArticleOfCell:sender
{
/* this method will be called from oNewsGroupNXBrowser's cell */
/* "markAllArticleAsRead:" will triger it */
id newsGroup;
id groupInfo;
newsGroup = [[sender node] linkedData];
groupInfo = [newsGroup dataForKey:GROUPINFO];
[groupInfo markAllArticle];
return self;
}
- getNewArticles:sender
{
if ([iNntpIO reconnectServer:sender] == nil) {
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("Can not recconect to nntp server."), LoStr("OK"),NULL,NULL);
[NXApp terminate:self];
}
[oArticleNXBrowser setRootListnode:nil];
[oArticleNXBrowser loadColumnZero];
return self;
}
- unSubscribeGroup:sender
{
id lastColumnMatrix;
switch(NXRunAlertPanel(LoStr("NewsBase"),
LoStr("Cannot Undo! Selected newsgroup in browser will be unsubscribed."),
LoStr("OK"),LoStr("Cancel"),NULL)) {
case NX_ALERTDEFAULT:
lastColumnMatrix = [oNewsGroupNXBrowser matrixInColumn:
[oNewsGroupNXBrowser lastColumn]];
[lastColumnMatrix sendAction:@selector(unSubscribeGroupOfCell:)
to:self forAllCells:NO];
/* reset oNewsGroupNXBrowser browser */
[lastColumnMatrix display];
break;
case NX_ALERTALTERNATE:
break;
}
return (self);
}
- unSubscribeGroupOfCell:sender
{
/* this method will be called from oNewsGroupNXBrowser's cell */
/* "unSubscribeGroup:" will triger it */
id node;
id groupInfo;
node = [sender node];
groupInfo = [[node linkedData] dataForKey:GROUPINFO];
[groupInfo addInfoString:"no" key:SUBSCRIBE];
[node setActive:NO];
[sender setActive:NO];
return self;
}
- _nodeForSelectedCellInBrowser:kbrowser
{
id lastColumnMatrix;
id selectedCell;
lastColumnMatrix = [kbrowser matrixInColumn:[kbrowser lastColumn]];
selectedCell = [lastColumnMatrix selectedCell];
return [selectedCell node];
}
- (int)openNewsBasePanel
{
const char *servername;
int returnCode;
servername = NXGetDefaultValue(OWNER, NNTPSERVER);
DBG(10,fprintf(stderr,"default value nntpserver=%s",servername));
[oOpenNewsBasePanel makeKeyAndOrderFront:self];
[oNntpServerNameField setStringValue:(char *)servername];
returnCode = [NXApp runModalFor:oOpenNewsBasePanel];
[oOpenNewsBasePanel free];
return(returnCode);
}
- cancelConnect:sender
{
[NXApp stopModal:0];
return self;
}
- okConnect:sender
{
strncpy(iNntpHost, [oNntpServerNameField stringValue],
(sizeof(iNntpHost)-1));
if ([[oGroupSelectionButton selectedCell] tag]==0) {
iAllNewsFlag = NO;
} else {
iAllNewsFlag = YES;
}
[NXApp stopModal:1];
return self;
}
- windowDidBecomeKey:sender
{
[[NXApp delegate] browserDidBecomeKey:self];
return(self);
}
- windowDidResignKey:sender
{
[[NXApp delegate] browserDidResignKey:self];
return(self);
}
- windowWillClose:sender
{
[self _saveWindowInfoToDefaultDB];
[[NXApp delegate] browserDidResignKey:self];
[NXApp delayedFree:self];
return(self);
}
- _saveWindowInfoToDefaultDB
{
NXRect newsbaseRect;
NXRect folderDockRect, browserViewRect, leftSideRect, rightSideRect;
char buffer[256];
// +----------------------+ -+
// | folderDock | newsbaseRect
// +----------------------+ |
// | | | |
// |leftSide| | |
// | | | |
// +----------------------+ -+
// save .newsrc file
[iNntpIO saveNewsRcFile];
// save .dir.newsbase file
[oNewsfolderDockMatrix saveDirFile];
// save NewsBase frameSize and location of divider
[oNewsReader getFrame:&newsbaseRect];
[oNewsfolderDock getFrame:&folderDockRect];
[oBrowserSplitView getFrame:&browserViewRect];
[oNewsgroupView getFrame:&leftSideRect];
[oArticleNXBrowser getFrame:&rightSideRect];
sprintf(buffer, "(%.0f,%.0f):(%.0f,%.0f):"
"(%.0f,%.0f):(%.0f,%.0f):(%.0f,%.0f):(%.0f,%.0f)",
newsbaseRect.origin.x, newsbaseRect.origin.y,
newsbaseRect.size.width, newsbaseRect.size.height,
folderDockRect.size.width, folderDockRect.size.height,
browserViewRect.size.width, browserViewRect.size.height,
leftSideRect.size.width, leftSideRect.size.height,
rightSideRect.size.width, rightSideRect.size.height);
NXWriteDefault(OWNER, NNTPBROWSER_FRAME, buffer);
return self;
}
- free
{
if (iNntpIO != nil) {
[iNntpIO saveNewsRcFile];
[iNntpIO free];
}
[oNewsReader free];
[oGetArticleNumWindow free];
[self perform:@selector(destroyZone:) with:nil afterDelay:1
cancelPrevious:NO];
return(nil);
}
- destroyZone:dummy
{
NXDestroyZone(newsbaseZone);
[super free];
return(nil);
}
/* delegate method for NXSplitView */
#define SCRLLMATRIX_HEIGHT 107 // height for oNewsfolderScroll
- splitView:sender resizeSubviews:(const NXSize *)oldSize
{
id upperView, lowerView;
NXRect viewFrame, upperFrame;
int ncols, nrows;
int i, j;
NXSize cellSize, intercell;
int numRows, numCols;
DBG(1,fprintf(stderr,"-- splitView:\n"));
// upperView = *(NX_ADDRESS([sender subviews]));
// lowerView = *(NX_ADDRESS([sender subviews]) + 1);
upperView = oNewsfolderDock;
lowerView = oBrowserSplitView;
[[sender window] disableDisplay];
[sender adjustSubviews];
// adjust upper(self) view size
[sender getFrame:&viewFrame];
[upperView getFrame:&upperFrame]; // upperView is ScrollView
// and oNewsfolderDockMatrix is a docView of that ScrollView
[oNewsfolderDockMatrix getCellSize:&cellSize];
[oNewsfolderDockMatrix getIntercell:&intercell];
[oNewsfolderDockMatrix getEnoughNumRows:&nrows numCols:&ncols
forSize:&(upperFrame.size)];
upperFrame.size.height = cellSize.height * nrows +
intercell.height * (nrows-1);
[upperView setFrame:&upperFrame];
// compute lower view size
viewFrame.origin.y = [sender dividerHeight] + upperFrame.size.height;
// coord. is flipped in NXSplitView
viewFrame.size.height -= viewFrame.origin.y;
[lowerView setFrame:&viewFrame];
[[sender window] reenableDisplay];
// unregister cell's frame to viewRectList in AcceptWindow
// so that the clipped cell can not be used as dropped well
[oNewsfolderDockMatrix getNumRows:&numRows numCols:&numCols];
if (numCols > ncols) {
// remove columns
for (i = (numCols-1); i > (ncols-1); --i) {
// unregister rect of cell which will be clipped by ScrollView,
// which is a superview of this class
for (j = (numRows-1); j >= 0; --j) {
[oNewsfolderDockMatrix unregisterCellAt:j :i window:nil];
}
}
}
if (numRows > nrows) {
// remove rows
for (i = (numRows-1); i > (nrows-1); --i) {
// unregister rect of cell which will be clipped by ScrollView,
// which is a superview of this class
for (j = (numCols-1); j >= 0; --j) {
[oNewsfolderDockMatrix unregisterCellAt:i :j window:nil];
}
}
}
// reregister the cells in Scroll view
[oNewsfolderScrollMatrix registerCells];
return self;
}
- splitView:sender getMinY:(NXCoord *)minY maxY:(NXCoord *)maxY
ofSubviewAt:(int)offset
{
NXRect viewFrame;
int nrows, ncols;
id upperView, lowerView;
NXSize cellSize, intercell;
upperView = oNewsfolderDockMatrix;
lowerView = oBrowserSplitView;
[upperView getCellSize:&cellSize];
[upperView getIntercell:&intercell];
*minY = 0.0;
[sender getFrame:&viewFrame];
viewFrame.size.height -= SCRLLMATRIX_HEIGHT;
[upperView getEnoughNumRows:&nrows numCols:&ncols
forSize:&(viewFrame.size)];
nrows -= 1; // avoid that the upperview size will be
// overflow because of rounding nrows
if (nrows >= 1) {
*maxY = cellSize.height * nrows + intercell.height * (nrows -1);
} else {
*maxY = 0.0;
}
return self;
}
@end